package com.my.swas.sso.module.admin.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.base.Joiner;
import com.my.swas.common.jwt.JWTToken;
import com.my.swas.common.jwt.JWTUtils;
import com.my.swas.common.utils.CookieUtils;
import com.my.swas.common.utils.MD5Utils;
import com.my.swas.sso.common.base.BaseController;
import com.my.swas.sso.common.config.properties.SSOProperties;
import com.my.swas.sso.common.constans.CacheConst;
import com.my.swas.common.constans.CommConst;
import com.my.swas.sso.module.admin.entity.Role;
import com.my.swas.sso.module.admin.entity.User;
import com.my.swas.sso.enums.OperationType;
import com.my.swas.sso.module.admin.dto.UserDto;
import com.my.swas.sso.module.admin.service.UserService;
import com.my.swas.sso.module.admin.vo.ResTreeSelectVo;
import com.my.swas.sso.module.admin.vo.UserVo;
import jodd.util.BCrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: :MaYong
 */
@Slf4j
@Controller
@RequestMapping("admin")
public class WebController extends BaseController {
    @Resource
    private UserService userService;


    @Resource
    private SSOProperties ssoProperties;


    @GetMapping(value = {"login", ""})
    public String login() {
        Boolean isAuth = SecurityUtils.getSubject().isAuthenticated();
        if (isAuth) {
            return "redirect:/admin/main";
        }
        return "home/login";
    }

    @PostMapping(value = "login")
    public String toLogin(@RequestParam("userAccount") String userAccount,
                          @RequestParam("password") String password,
                          Model model,
                          HttpServletResponse response) {
        User user = new User();
        user.setUserAccount(userAccount);
        User userBean = userService.getOne(new QueryWrapper<>(user));
        if (userBean == null) {
            model.addAttribute("message", "请填写正确的用户名和密码");
            return "home/login";
        }
        //验证帐号是否已经锁定
        if (CommConst.NO.equals(userBean.getEnable())) {
            model.addAttribute("message", "账户已经锁定，请联系管理员解锁");
            return "home/login";
        }
        //验证错误登录次数
        if (null != userBean.getVerifyCount()) {
            if (CommConst.FIVE.compareTo(userBean.getVerifyCount()) <= 0) {
                model.addAttribute("message", "验证未通过错误次数过多");
                return "home/login";
            }
        }

        //判断密码是否正确
        if (!BCrypt.checkpw(password, userBean.getPassword())) {
            userService.verifyCount(userBean.getId(), userBean.getVerifyCount(), OperationType.PLUS);
            model.addAttribute("message", "请填写正确的用户名和密码");
            return "home/login";
        }
        //下面可以直接返回jwtToken.但是为了更好的理解和应用加一层利用shiro验证机制登录的逻辑
        String sign = JWTUtils.sign(userBean.getUserAccount(), userBean.getPassword(), userBean.getId());
        //获取当前的Subject
        Subject subject = SecurityUtils.getSubject();
        JWTToken jwtToken = new JWTToken(sign);
        CookieUtils.setCookie(response, JWTToken.AUTH_TOKEN, sign, ssoProperties.getCookieDomain());
        try {
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法
            log.info("对用户[" + userAccount + "]进行登录验证..验证开始");
            subject.login(jwtToken);
        } catch (Exception uae) {
            model.addAttribute("message", uae.getMessage());
        }
        //验证是否登录成功
        if (subject.isAuthenticated()) {
            log.info("用户[" + userAccount + "]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)");
            setUser(userBean);
            refreshMainTree(jwtToken);
            return "redirect:/admin/main";
        } else {
            jwtToken.clear();
            return "home/login";
        }
    }

    @GetMapping("register")
    public String toRegister() {
        return "user/register";
    }


    @PostMapping(value = "register", produces = "application/json;charset=utf-8")
    public String register(UserDto userDto,
                           Model model,
                           HttpServletResponse response) {
        if (!userDto.getFirstPassword().equals(userDto.getSecondPassword())) {
            model.addAttribute("message", "两次输入的密码不一致，请重新输入");
            return "user/register";
        }
        User user = new User();
        user.setUserAccount(userDto.getUserAccount());
        User verifyUser = userService.getOne(new QueryWrapper<>(user));
        if (null != verifyUser) {
            model.addAttribute("message", "该用户已被占用");
            return "user/register";
        }
        User u = new User();
        u.setPassword(MD5Utils.md5(userDto.getFirstPassword(), CommConst.TWO));
        u.setUserAccount(userDto.getUserAccount());
        u.setEnable(CommConst.ONE);
        u.setVerifyCount(CommConst.ZERO);
        u.setStatus(CommConst.ONE);
        Boolean flag = userService.save(u);
        userDto.setRoleIds("3,1");
        if (flag) {
            model.addAttribute("message", "该用户已被占用");
            return "user/register";
        }
        String sign = JWTUtils.sign(u.getUserAccount(), u.getPassword(), u.getId());
        model.addAttribute("sign", sign);
        CookieUtils.setCookie(response, JWTToken.AUTH_TOKEN, sign, ssoProperties.getCookieDomain());

        //获取当前的Subject
        Subject currentUser = SecurityUtils.getSubject();
        JWTToken jwtToken = new JWTToken(sign);
        currentUser.login(jwtToken);
        if (currentUser.isAuthenticated()) {
            return "redirect:/admin/main";
        } else {
            jwtToken.clear();
            return "redirect:/admin/login";
        }
    }


    @RequestMapping(value = "main")
    public String main(Model model) {
        UserVo userVos = userService.getUserVo(JWTUtils.getUserId(null));
        String roleNames = Joiner.on(",").join(userVos.getRoleList().stream().filter(u -> StrUtil.isNotEmpty(u.getRoleTips())).map(Role::getRoleTips).collect(Collectors.toSet()));
        model.addAttribute("user", getUser());
        model.addAttribute("roleNames", roleNames);
        String key = CacheConst.EH_MAIN_TREE + getUserId();
        String value = cacheUtils.getStr(key);
        List<ResTreeSelectVo> resTreeSelectVoList;
        if (StrUtil.isBlank(value)) {
            resTreeSelectVoList = refreshMainTree();
        } else {
            resTreeSelectVoList = JSONObject.parseObject(value, new TypeReference<List<ResTreeSelectVo>>() {
            });
        }
        model.addAttribute("menuTree", resTreeSelectVoList);
        return "layui/home/index";
    }

    /**
     * 首页数据
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "index")
    public String index(Model model) {
        return "home/index";
    }

    @GetMapping("logout")
    public String logout() {
        SecurityUtils.getSubject().logout();
        refreshMainTree();
        return "redirect:/admin/login";
    }

    @GetMapping("goToUrl")
    public String goToUrl(String url) {
        return url;
    }


}
